package myutil

import (
	"errors"
	"unsafe"
)

// RecycleQueue implement recycle queue
// 支持对传入的切片进行循环CRUD（插入、删除、更新或读取）操作
type RecycleQueue struct {
	n     uint             // 当前插入的总数量，这个数量可能大于总容量cap值，需要考虑整型的溢出问题
	head  uint             // 数据头部
	tail  uint             // 数据尾部
	Cap   uint             // 切片的总长度
	Slice []unsafe.Pointer // 考虑分配内存的效率，切片必须为指针类型，对切片指针对应的真实数据类型不感知
}

// Append to slice
func (r *RecycleQueue) Append(element unsafe.Pointer) (head, tail uint) {
	i := r.n % r.Cap
	r.Slice[i] = element
	r.n++
	r.tail = i

	if r.n <= r.Cap {
		return r.head, r.tail
	}

	if r.head == r.tail {
		r.head = i + 1
	}

	return r.head, r.tail
}

// Select to slice
// 如果n大于cap时，返回两段
func (r *RecycleQueue) Select() ([]unsafe.Pointer, []unsafe.Pointer) {
	if r.head == r.tail {
		if r.Slice[r.head] == nil {
			return nil, nil
		}
		return r.Slice[r.head : r.tail+1], nil
	} else if r.head < r.tail {
		return r.Slice[r.head : r.tail+1], nil
	}

	return r.Slice[r.head:r.Cap], r.Slice[:r.tail+1]
}

// Update to slice
func (r *RecycleQueue) Update(element unsafe.Pointer, offset uint) error {
	if offset < r.Cap {
		r.Slice[offset] = element
		return nil
	}

	return errors.New("out range of slice")
}

// Delete to slice
// 删除动作只能删除队列头部的数据，保持数据的联系性
func (r *RecycleQueue) Delete() {
	r.Slice[r.head] = nil
	if r.head == r.tail {
		return
	}

	r.head = (r.head + 1) % r.Cap
	return
}
